Java Differences topic

Syntactic and semantic differences between Java and the generated Dart bindings

This document highlights the key syntactic and semantic variations between Java and Dart and how JNIgen addresses them to ensure smooth interoperability.

Method overloading

Java supports overloading methods. This means that it can distinguish between two methods with the same name that have a different signature.

// Java
public class Calculator {
  public int add(int a, int b) {
    return a + b;
  }

  public double add(double a, double b) {
    return a + b;
  }

  public float add(float a, float b) {
    return a + b;
  }
}

This is not the case for Dart. Each method of a class must have a unique name. To overcome this limitation, JNIgen adds a dollar sign ($) and a numeric suffix to the end of the overloaded method name.

// Dart Bindings - Boilerplate omitted for clarity.
class Calculator extends JObject {
  int add(int a, int b) { /* ... */ }

  double add$1(double a, double b) { /* ... */ }

  double add$2(double a, double b) { /* ... */ }
}

Warning

Running the code generator again on a different version of the library can map the methods differently if the order of the methods change or another overloading of the same method gets added.

Double check the doc comments on the generated methods to make sure you are calling your intended method.

You might wonder why the method isn't renamed to add1 instead of add$1. The reason is that a method named add1 could already exist in the Java class. On the other hand, Java identifiers normally do not contain dollar signs.

Note

See Identifiers containing dollar signs to see what JNIgen does when identifiers contain dollar signs.

// Java
public class Calculator {
  public int add(int a, int b) {
    return a + b;
  }

  public double add(double a, double b) {
    return a + b;
  }

  public float add(float a, float b) {
    return a + b;
  }

  public int add1(int a) {
    return a + 1;
  }

  public double add1(double a) {
    return a + 1;
  }
}

In this case, the generated code will be:

// Dart Bindings - Boilerplate omitted for clarity.
class Calculator extends JObject {
  int add(int a, int b) { /* ... */ }

  double add$1(double a, double b) { /* ... */ }

  double add$2(double a, double b) { /* ... */ }

  int add1(int a) { /* ... */ }

  double add1$1(double a) { /* ... */ }
}

Fields and methods with the same name

In Java, we can have a field and a method with the same name. This is not possible in Dart.

// Java
public class Player {
  // Player's personal duck!
  public Duck duck;

  // Lower your head!
  public void duck() { /* ... */ }
}

JNIgen handles this similarly to method overloading. The method with the same name as the field will be appended by a dollar sign ($) followed by a numeric suffix.

// Dart Bindings - Boilerplate omitted for clarity.
class Player extends JObject {
  Duck get duck { /* ... */ };
  set duck(Duck value) { /* ... */ }

  void duck$1() { /* ... */ }

  // If there were more `duck` methods they would be named
  // `duck$2`, `duck$3`, ...
}

It is important to note that the order of renaming is fields-first methods-second. So when both a field named duck and a method named duck exist, the field keeps its original name as seen above.

However the renaming happens for superclasses first. Consider this case.

// Java
public class Player {
  // Lower your head!
  public void duck() { /* ... */ }
}

public class DuckOwningPlayer extends Player {
  // Player's personal duck!
  public Duck duck;
}

The Player class already has a method named duck and no field with the same name. So this will be the generated bindings for it:

// Dart Bindings - Boilerplate omitted for clarity.
class Player extends JObject {
  void duck() { /* ... */ }
}

DuckOwningPlayer inherits the duck() method from Player and adds a field named duck. This time, the field will be renamed as the method is simply inherited.

// Dart Bindings - Boilerplate omitted for clarity.
class DuckOwningPlayer extends Player {
  Duck get duck$1 { /* ... */ };
  set duck$1(Duck value) { /* ... */ }
}

Identifiers containing dollar signs

JNIgen uses dollar signs in the generated code to fill the syntactic and semantic gaps between Java and Dart. This normally does not cause a problem as the Java language specificifaction suggests dollar signs should be used only in the generated code or, rarely, to access pre-existing names on legacy systems.

JNIgen replaces each single dollar sign with two dollar signs. For example generated$method$2 will turn into generated$$method$$2. This prevents name collision as JNIgen-renamed identifiers will end with an odd number of dollar signs (optionally followed by a numeric suffix).

Identifier starting with underscore (_)

Unlike Java, Dart identifiers that start with an underscore are private. This means they are inaccessible outside their defining scope. Users should still be able to access public Java identifiers that start with an underscore from the generated Dart bindings. To allow this, JNIgen prepends such identifiers with a dollar sign to keep them public in Dart.

For example, _Example in Java will be converted to $_Example in the Dart bindings:

// Java
public class _Example {
  public void _printMessage() {
    System.out.println("Hello from Java!");
  }
}
// Dart Bindings - Boilerplate omitted for clarity.
class $_Example extends JObject {
  void $_printMessage() { /* ... */ }
}

Inner classes

Java has the concept of inner classes, while Dart does not. Therefore, inner classes are generated as separate classes named using the name of their outer-class followed by a dollar sign ($) followed by their original name.

For example:

// Java
public class Outer {
  public class Inner {}
}

will be turned into:

// Dart Bindings - Boilerplate omitted for clarity.
class Outer extends JObject {}

class Outer$Inner extends JObject {}

Libraries

jnigen Java Differences Lifecycle Threading Interface Implementation
This library exports a high level programmatic API to jnigen, the entry point of which is runJniGenTask function, which takes run configuration as a JniGenTask.